package com.situ.vivamarket.model;

import com.fasterxml.jackson.annotation.*;
import jakarta.validation.constraints.NotEmpty;
import jakarta.validation.constraints.NotNull;
import lombok.EqualsAndHashCode;
import lombok.Getter;
import lombok.Setter;
import lombok.ToString;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

@Setter
@Getter
@EqualsAndHashCode(onlyExplicitlyIncluded = true)
@ToString(exclude = {"parent", "children"})
@JsonIgnoreProperties("handler")
public class Category implements Serializable, Cloneable{
    @EqualsAndHashCode.Include
    private Integer id;
    @NotEmpty(message = "品牌名不能为空")
    private String name;
    private String alias;
    private String iconCls;//图标
    private int seq;//顺序号
    private String description;
    @NotNull(message = "父类别不能为空")
    private Integer parentId;
    @JsonBackReference
    private Category parent;//父类别，为null则为根节点
    @JsonManagedReference
    private List<Category> children;//子类别

    public String getParentChain(){
        StringBuilder sb = new StringBuilder();
        Category parent = getParent();
        while(parent != null){
            sb.append(parent.getName()+"∈");
            parent = parent.getParent();
        }
        String result = sb.toString();
        if(result.endsWith("∈")){
            result = result.substring(0, result.length()-1);
        }
        return result;
    }

    //名称链
    public List<String> getChain() {
        List<String> list = new ArrayList<>();
        list.add(this.name);
        if (parent != null) {
            list.addAll(parent.getChain());
        }
        return list;
    }

    /**
     * 构建类别树
     *
     * @param categories 所有类别实体
     * @return 类别树
     */
    public static Category buildCategoryTree(List<Category> categories) {
        Map<Integer, Category> cache = new HashMap<>();

        //此处进行克隆处理是因为，categories是从caffeine中获取的缓存数据，不能直接修改，若直接修改，就修改了缓存中的数据
        try {
            for (Category category : categories) {
                cache.put(category.getId(), (Category) category.clone());
            }
        } catch (CloneNotSupportedException e) {
            throw new RuntimeException(e);
        }

        //所有一级节点
        List<Category> roots = new ArrayList<>();

        for (Category c : cache.values()) {//不能遍历从caffeine中获取的categories，而要遍历克隆过的
            if (c.getParentId() == null) {//假设其为根节点
                roots.add(c);
            } else {
                Integer parentId = c.getParentId();//获取父节点编号
                Category parent = cache.get(parentId);
                if (parent == null) {
                    throw new RuntimeException("无效的父节点编号");
                }
                if (parent.getChildren() == null) {
                    parent.setChildren(new ArrayList<>());
                }
                //建立双向关联。
                //如果已经被添加过，则不再重复添加，一是防止数据中出现相同节点的情况，二是防止caffeine中获取的数据已经树化，再次重复添加的情况
                if (!parent.getChildren().contains(c)) {
                    parent.getChildren().add(c);
                    c.setParent(parent);
                }
            }
        }

        Category root;//唯一根节点
        if (roots.isEmpty()) {
            throw new RuntimeException("无根节点");
        } else if (roots.size() == 1) {
            root = roots.getFirst();
        } else {
            root = createRoot();
            roots.forEach(t -> {
                t.setParent(root);
                root.getChildren().add(t);
            });
        }
        return root;
    }


    //创建一个空根节点
    private static Category createRoot() {
        Category root = new Category();
        root.setId(0);
        root.setName("全部种类");
        root.setChildren(new ArrayList<>());
        return root;
    }

    @Override
    public Object clone() throws CloneNotSupportedException {
        return super.clone();
    }

}
